<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
	<meta name="keywords" content="nacos1.3.0,kernel" />
	<meta name="description" content="Nacos 1.3.0 new kernel construction process" />
	<!-- 网页标签标题 -->
	<title>Nacos 1.3.0 new kernel construction process</title>
	<link rel="shortcut icon" href="https://img.alicdn.com/tfs/TB1hgJpHAPoK1RjSZKbXXX1IXXa-64-64.png"/>
	<link rel="stylesheet" href="/build/blogDetail.css" />
</head>
<body>
	<div id="root"><div class="blog-detail-page" data-reactroot="" data-reactid="1" data-react-checksum="-479273620"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/en-us/index.html" data-reactid="4"><img class="logo" src="/img/nacos_colorful.png" data-reactid="5"/></a><div class="search search-normal" data-reactid="6"><span class="icon-search" data-reactid="7"></span></div><span class="language-switch language-switch-normal" data-reactid="8">中</span><div class="header-menu" data-reactid="9"><img class="header-menu-toggle" src="/img/menu_gray.png" data-reactid="10"/><ul data-reactid="11"><li class="menu-item menu-item-normal" data-reactid="12"><a href="/en-us/index.html" data-reactid="13">HOME</a></li><li class="menu-item menu-item-normal" data-reactid="14"><a href="/en-us/docs/quick-start.html" data-reactid="15">DOCS</a></li><li class="menu-item menu-item-normal menu-item-normal-active" data-reactid="16"><a href="/en-us/blog" data-reactid="17">BLOG</a></li><li class="menu-item menu-item-normal" data-reactid="18"><a href="/en-us/community" data-reactid="19">COMMUNITY</a></li><li class="menu-item menu-item-normal" data-reactid="20"><a href="https://cn.aliyun.com/product/aliware/mse?spm=nacos-website.topbar.0.0.0" data-reactid="21">NACOS IN CLOUD</a><img class="menu-img" src="https://img.alicdn.com/tfs/TB1esl_m.T1gK0jSZFrXXcNCXXa-200-200.png" data-reactid="22"/></li><li class="menu-item menu-item-normal" data-reactid="23"><a href="https://job.alibaba.com/zhaopin/position_detail.htm?trace=qrcode_share&amp;positionCode=GP633620" data-reactid="24">HIRING</a><img class="menu-img" src="https://img.alicdn.com/tfs/TB1esl_m.T1gK0jSZFrXXcNCXXa-200-200.png" data-reactid="25"/></li><li class="menu-item menu-item-normal" data-reactid="26"><a href="http://console.nacos.io/nacos/index.html" data-reactid="27">DEMO-CONSOLE</a></li></ul></div></div></header><section class="blog-content markdown-body" data-reactid="28"><h1>Nacos 1.3.0 Documentation of features and functionality</h1>
<p><a name="0YIG0"></a></p>
<h2>Summarize</h2>
<p>This 1.3.0 is implanted to a great extent, involving the modification of two large modules and the addition of a core module</p>
<ol>
<li>nacos-core module modification
<ol>
<li>nacos</li>
<li>nacos internal event mechanism</li>
<li>nacos consistency protocol layer</li>
</ol>
</li>
<li>nacos-config module modification
<ol>
<li>Add embedded distributed data storage components</li>
<li>Separation of embedded storage and external storage</li>
<li>Simple operation and maintenance of embedded storage</li>
</ol>
</li>
<li>Add nacos-consistency module
<ol>
<li>Unified abstraction for AP protocol and CP protocol</li>
</ol>
</li>
</ol>
<br />
<a name="rnkDY"></a>
## 系统参数变化
<a name="1Gmg9"></a>
### 新增
<table>
<thead>
<tr>
<th style="text-align:center"><strong>core模块</strong></th>
<th>nacos.watch-file.max-dirs</th>
<th>JVM parameter</th>
<th>Maximum number of monitored directories</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center"></td>
<td>nacos.core.notify.ring-buffer-size</td>
<td>JVM parameter</td>
<td>Quick notification of the maximum length of the queue</td>
</tr>
<tr>
<td style="text-align:center"></td>
<td>nacos.core.notify.share-buffer-size</td>
<td>JVM parameter</td>
<td>The maximum length of the slow notification queue</td>
</tr>
<tr>
<td style="text-align:center"></td>
<td>nacos.core.member.fail-access-cnt</td>
<td>JVM parameter.properties</td>
<td>Maximum number of failed visits to cluster member nodes</td>
</tr>
<tr>
<td style="text-align:center"></td>
<td>nacos.core.address-server.retry</td>
<td>JVM parameter、application.properties</td>
<td>Address server addressing mode, first start request retry times</td>
</tr>
</tbody>
</table>
<br />
<a name="kxo8O"></a>
## The future overall logical architecture of Nacos and its components
![1561217775318-6e408805-18bb-4242-b4e9-83c5b929b469.png](https://cdn.nlark.com/yuque/0/2020/png/333972/1587129046320-5a286f38-8db4-4e76-9b42-8bd859f51a60.png#align=left&display=inline&height=1184&margin=%5Bobject%20Object%5D&name=1561217775318-6e408805-18bb-4242-b4e9-83c5b929b469.png&originHeight=1184&originWidth=1608&size=279074&status=done&style=none&width=1608)
<a name="Hyc6u"></a>
## Nacos cluster member node addressing mode
<p><br />Before 1.3.0, nacos' naming module and config module had their own member list management tasks. In order to unify the replacement mode of nacos assigning the next member list, the implementation of merge management is replaced from the named module and the config module, unified to the addressing module of the core module, and the command line parameters are added at the same time -Dnacos.member.list **To set the list listed by nacos, this parameter can be called an alternative to the cluster.conf file. The current nacos addressing mode categories are as follows</p>
<ol>
<li>In stand-alone mode: StandaloneMemberLookup</li>
<li>Play mode
<ol>
<li>The cluster.conf file exists: FileConfigMemberLookup</li>
<li>The cluster.conf file does not exist or -Dnacos.member.list is not set: AddressServerMemberLookup</li>
</ol>
</li>
</ol>
<p>If you want to specify an addressing mode, set this parameter：<strong>nacos.core.member.lookup.type=[file,address-server]</strong></p>
<p>The logical diagram is as follows
<img src="https://cdn.nlark.com/yuque/__puml/e209a677aa8b5ffce23589e987ee5129.svg#lake_card_v2=eyJjb2RlIjoiQHN0YXJ0dW1sXG5cbigqKSAtLT4gXCJMb29rdXBGYWN0b3J5LmluaXQoKVwiXG5cbmlmIFwic3RhbmRhbG9uZSBtb2RlXCIgdGhlblxuICAtLT5bdHJ1ZV0gXCJyZXR1cm4gU3RhbmRhbG9uZU1lbWJlckxvb2t1cFwiXG4gIC0tPiBMb29rdXAucnVuKClcbmVsc2VcbiBpZiBcImNsdXN0ZXIuY29uZiBleGlzdHNcIiB0aGVuXG4gICAgLS0-W3RydWVdIFwicmV0dXJuIEZpbGVDb25maWdNZW1iZXJMb29rdXBcIlxuICAgIC0tPiBMb29rdXAucnVuKClcbiBlbHNlXG4gICAgLT5bZmFsc2VdIFwicmV0dXJuIEFkZHJlc3NTZXJ2ZXJNZW1iZXJMb29rdXBcIlxuICAgIC0tPiBMb29rdXAucnVuKClcbiBlbmRpZlxuZW5kaWZcblxuLS0-ICgqKVxuXG5AZW5kdW1sIiwidHlwZSI6InB1bWwiLCJpZCI6IlplWGtkIiwidXJsIjoiaHR0cHM6Ly9jZG4ubmxhcmsuY29tL3l1cXVlL19fcHVtbC9lMjA5YTY3N2FhOGI1ZmZjZTIzNTg5ZTk4N2VlNTEyOS5zdmciLCJjYXJkIjoiZGlhZ3JhbSJ9" alt=""></p>
<p><a name="wqkMp"></a></p>
<h3>Addressing mode details</h3>
<p>Next, I introduce two other addressing modes in addition to the addressing mode in stand-alone mode<br /></p>
<p><a name="egl3H"></a></p>
<h4>FileConfigMemberLookup</h4>
<p>This addressing mode is managed based on the cluster.conf file, and each node will read the list of member nodes in the cluster.conf file under their respective ${nacos.home}/conf and then form a cluster. And after reading the cluster.conf file under ${nacos.home}/conf for the first time, it will automatically register a directory listener with the operating system's <em><strong>inotify</strong></em> mechanism to monitor ${nacos.home}/ All file changes in the conf directory (note that only files will be monitored here, and file changes in subdirectories cannot be monitored)<br />When you need to expand or shrink the cluster nodes, you need to manually modify the content of the member node list of cluster.conf under ${nacos.home}/conf for each node.</p>
<pre><code class="language-java"><span class="hljs-keyword">private</span> FileWatcher watcher = <span class="hljs-keyword">new</span> FileWatcher() {
		<span class="hljs-meta">@Override</span>
		<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onChange</span><span class="hljs-params">(FileChangeEvent event)</span> </span>{
			readClusterConfFromDisk();
		}

		<span class="hljs-meta">@Override</span>
		<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">interest</span><span class="hljs-params">(String context)</span> </span>{
			<span class="hljs-keyword">return</span> StringUtils.contains(context, <span class="hljs-string">"cluster.conf"</span>);
		}
};

<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">start</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> NacosException </span>{
	readClusterConfFromDisk();

	<span class="hljs-keyword">if</span> (memberManager.getServerList().isEmpty()) {
		<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NacosException(NacosException.SERVER_ERROR,
					<span class="hljs-string">"Failed to initialize the member node, is empty"</span>);
	}

	<span class="hljs-comment">// Use the inotify mechanism to monitor file changes and automatically</span>
	<span class="hljs-comment">// trigger the reading of cluster.conf</span>
	<span class="hljs-keyword">try</span> {
		WatchFileCenter.registerWatcher(ApplicationUtils.getConfFilePath(), watcher);
	}
	<span class="hljs-keyword">catch</span> (Throwable e) {
		Loggers.CLUSTER.error(<span class="hljs-string">"An exception occurred in the launch file monitor : {}"</span>, e);
	}
}
</code></pre>
<p>The first time you directly read the node list information in the cluster.conf file, then register a directory listener with WatchFileCenter, and automatically trigger <em><strong>readClusterConfFromDisk()</strong></em> to re-read cluster.conf when the cluster.conf file changes file<br /><img src="https://cdn.nlark.com/yuque/0/2020/png/333972/1591014354207-49c1e934-2aa5-465a-8a2b-0b09902814f8.png#align=left&amp;display=inline&amp;height=531&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=531&amp;originWidth=1169&amp;size=105696&amp;status=done&amp;style=none&amp;width=1169" alt="image.png">
<a name="yFTCl"></a></p>
<h4>AddressServerMemberLookup</h4>
<p>This addressing mode is based on an additional web server to manage cluster.conf. Each node periodically requests the content of the cluster.conf file from the web server, and then implements addressing between cluster nodes and expansion and contraction. <br />When you need to expand or shrink the cluster, you only need to modify the cluster.conf file, and then each node will automatically get the latest cluster.conf file content when it requests the address server.</p>
<pre><code class="language-java"><span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">start</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> NacosException </span>{
	<span class="hljs-keyword">if</span> (start.compareAndSet(<span class="hljs-keyword">false</span>, <span class="hljs-keyword">true</span>)) {
		<span class="hljs-keyword">this</span>.maxFailCount = Integer.parseInt(ApplicationUtils.getProperty(<span class="hljs-string">"maxHealthCheckFailCount"</span>, <span class="hljs-string">"12"</span>));
		initAddressSys();
		run();
	}
}

<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initAddressSys</span><span class="hljs-params">()</span> </span>{
	String envDomainName = System.getenv(<span class="hljs-string">"address_server_domain"</span>);
	<span class="hljs-keyword">if</span> (StringUtils.isBlank(envDomainName)) {
		domainName = System.getProperty(<span class="hljs-string">"address.server.domain"</span>, <span class="hljs-string">"jmenv.tbsite.net"</span>);
	} <span class="hljs-keyword">else</span> {
		domainName = envDomainName;
	}
	String envAddressPort = System.getenv(<span class="hljs-string">"address_server_port"</span>);
	<span class="hljs-keyword">if</span> (StringUtils.isBlank(envAddressPort)) {
		addressPort = System.getProperty(<span class="hljs-string">"address.server.port"</span>, <span class="hljs-string">"8080"</span>);
	} <span class="hljs-keyword">else</span> {
		addressPort = envAddressPort;
	}
	addressUrl = System.getProperty(<span class="hljs-string">"address.server.url"</span>,
				ApplicationUtils.getContextPath() + <span class="hljs-string">"/"</span> + <span class="hljs-string">"serverlist"</span>);
	addressServerUrl = <span class="hljs-string">"http://"</span> + domainName + <span class="hljs-string">":"</span> + addressPort + addressUrl;
	envIdUrl = <span class="hljs-string">"http://"</span> + domainName + <span class="hljs-string">":"</span> + addressPort + <span class="hljs-string">"/env"</span>;

	Loggers.CORE.info(<span class="hljs-string">"ServerListService address-server port:"</span> + addressPort);
	Loggers.CORE.info(<span class="hljs-string">"ADDRESS_SERVER_URL:"</span> + addressServerUrl);
}

<span class="hljs-meta">@SuppressWarnings</span>(<span class="hljs-string">"PMD.UndefineMagicConstantRule"</span>)
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> NacosException </span>{
	<span class="hljs-comment">// With the address server, you need to perform a synchronous member node pull at startup</span>
	<span class="hljs-comment">// Repeat three times, successfully jump out</span>
	<span class="hljs-keyword">boolean</span> success = <span class="hljs-keyword">false</span>;
	Throwable ex = <span class="hljs-keyword">null</span>;
	<span class="hljs-keyword">int</span> maxRetry = ApplicationUtils.getProperty(<span class="hljs-string">"nacos.core.address-server.retry"</span>, Integer.class, <span class="hljs-number">5</span>);
	<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; maxRetry; i ++) {
		<span class="hljs-keyword">try</span> {
			syncFromAddressUrl();
			success = <span class="hljs-keyword">true</span>;
			<span class="hljs-keyword">break</span>;
		} <span class="hljs-keyword">catch</span> (Throwable e) {
			ex = e;
			Loggers.CLUSTER.error(<span class="hljs-string">"[serverlist] exception, error : {}"</span>, ExceptionUtil.getAllExceptionMsg(ex));
		}
	}
	<span class="hljs-keyword">if</span> (!success) {
		<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NacosException(NacosException.SERVER_ERROR, ex);
	}

	GlobalExecutor.scheduleByCommon(<span class="hljs-keyword">new</span> AddressServerSyncTask(), <span class="hljs-number">5_000L</span>);
}
</code></pre>
<p>During initialization, it will take the initiative to synchronize the current cluster member list information with the address server, and if it fails, retry, the maximum number of retries can be controlled by setting <em><strong>nacos.core.address-server.retry</strong></em>, The default is 5 times, and then after success, a scheduled task will be created to synchronize the cluster member node information to the address server<br /><img src="https://cdn.nlark.com/yuque/0/2020/png/333972/1591014362972-004f5338-af0d-4d0d-b769-4f3d5118c08a.png#align=left&amp;display=inline&amp;height=846&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=846&amp;originWidth=1149&amp;size=188886&amp;status=done&amp;style=none&amp;width=1149" alt="image.png">
<a name="sgOTI"></a></p>
<h3>How node management and addressing modes are combined</h3>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/333972/1591014400580-39b83aa0-c548-4241-a49e-0d72abda2a95.png#align=left&amp;display=inline&amp;height=715&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=715&amp;originWidth=1189&amp;size=131826&amp;status=done&amp;style=none&amp;width=1189" alt="image.png"><br />After MemberLookup starts, it will perform addressing tasks according to different addressing modes, will collect cluster node list information, call memberChange, trigger cluster node changes, and then publish node change events
<a name="idHpC"></a></p>
<h2>Nacos consensus protocol protocol layer abstraction</h2>
<p>From the overall architecture of nacos in the future, it can be seen that the consistency protocol layer will be the core module of nacos, and will serve each functional module built on the core module, or the service and core module itself. The consistency protocol needs to choose between availability and consistency because of the existence of partition fault tolerance, so there are two major types of consistency: final consistency and strong consistency. In nacos, both types of consistency protocols are possible. For example, the naming module uses AP and CP for data management of service instances, respectively. For the config module, it will involve the use of CP. At the same time, there are the following functional demand points</p>
<ol>
<li>At present, the persistence service uses a variant version of raft, and the business and the raft protocol are coupled. Therefore, it needs to be decoupled and decoupled. At the same time, a standard Java version of Raft is selected for implementation.</li>
<li>For small and medium-sized users, the configuration is basically not super much. An independent mysql is relatively heavy and requires a light-weight storage solution. It also supports 2.0 not dependent on mysql and 3.0 dependent on mysql configurability</li>
<li>Due to CP or AP, there are many implementations, how to make a good abstraction of the consistency protocol layer, so that in the future can quickly achieve the specific implementation of the underlying consistency protocol replacement, such as the Raft protocol, the current selection of nacos It is JRaft, it is not excluded that in the future nacos will implement a standard raft protocol or Paxos protocol by itself</li>
<li>Since there are multiple function modules working independently in Nacos, there can be no influence between each function module. For example, when the A module processes the request too slowly or an exception occurs, it cannot affect the normal operation of the B module, that is, each function module is in use. How to isolate the data processing of each module when using a consistent protocol?</li>
</ol>
<p>According to the consensus protocol and the above functional requirements, this time an abstract consensus protocol layer and related interfaces were made
<a name="3w8xM"></a></p>
<h3>Consensus agreement abstraction</h3>
<p><a name="p7zRo"></a></p>
<h4>ConsistencyProtocol</h4>
<p>The so-called consistency is the characteristic of whether multiple copies can maintain consistency, and the essence of the copy is data, and the operation of the data is either acquisition or modification. At the same time, the consensus protocol is actually for distributed situations, and this necessarily involves multiple nodes. Therefore, there is a need for a corresponding interface to be able to adjust the coordination protocol of the collaborative work node. What if we want to observe the operation of the consistency agreement? For example, the Raft protocol, we want to know who is the leader in the current cluster, the term of office, and who are the member nodes in the current cluster? Therefore, it is also necessary to provide a consistent protocol metadata acquisition. <br />In summary, the general design of ConsistencyProtcol can come out</p>
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">ConsistencyProtocol</span>&lt;<span class="hljs-title">T</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Config</span>, <span class="hljs-title">P</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">LogProcessor</span>&gt; <span class="hljs-keyword">extends</span> <span class="hljs-title">CommandOperations</span> </span>{

    <span class="hljs-comment">/**
     * Consistency protocol initialization: perform initialization operations based on the incoming Config
     * 一致性协议初始化，根据 Config 实现类
     *
     * <span class="hljs-doctag">@param</span> config {<span class="hljs-doctag">@link</span> Config}
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">init</span><span class="hljs-params">(T config)</span></span>;

    <span class="hljs-comment">/**
     * Add a log handler
     *
     * <span class="hljs-doctag">@param</span> processors {<span class="hljs-doctag">@link</span> LogProcessor}
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">addLogProcessors</span><span class="hljs-params">(Collection&lt;P&gt; processors)</span></span>;

    <span class="hljs-comment">/**
     * Copy of metadata information for this consensus protocol
     * 该一致性协议的元数据信息
     *
     * <span class="hljs-doctag">@return</span> metaData {<span class="hljs-doctag">@link</span> ProtocolMetaData}
     */</span>
    <span class="hljs-function">ProtocolMetaData <span class="hljs-title">protocolMetaData</span><span class="hljs-params">()</span></span>;

    <span class="hljs-comment">/**
     * Obtain data according to the request
     *
     * <span class="hljs-doctag">@param</span> request request
     * <span class="hljs-doctag">@return</span> data {<span class="hljs-doctag">@link</span> Response}
     * <span class="hljs-doctag">@throws</span> Exception
     */</span>
    <span class="hljs-function">Response <span class="hljs-title">getData</span><span class="hljs-params">(GetRequest request)</span> <span class="hljs-keyword">throws</span> Exception</span>;

    <span class="hljs-comment">/**
     * Get data asynchronously
     *
     * <span class="hljs-doctag">@param</span> request request
     * <span class="hljs-doctag">@return</span> data {<span class="hljs-doctag">@link</span> CompletableFuture&lt;Response&gt;}
     */</span>
    <span class="hljs-function">CompletableFuture&lt;Response&gt; <span class="hljs-title">aGetData</span><span class="hljs-params">(GetRequest request)</span></span>;

    <span class="hljs-comment">/**
     * Data operation, returning submission results synchronously
     * 同步数据提交，在 Datum 中已携带相应的数据操作信息
     *
     * <span class="hljs-doctag">@param</span> data {<span class="hljs-doctag">@link</span> Log}
     * <span class="hljs-doctag">@return</span> submit operation result {<span class="hljs-doctag">@link</span> Response}
     * <span class="hljs-doctag">@throws</span> Exception
     */</span>
    <span class="hljs-function">Response <span class="hljs-title">submit</span><span class="hljs-params">(Log data)</span> <span class="hljs-keyword">throws</span> Exception</span>;

    <span class="hljs-comment">/**
     * Data submission operation, returning submission results asynchronously
     * 异步数据提交，在 Datum 中已携带相应的数据操作信息，返回一个Future，自行操作，提交发生的异常会在CompleteFuture中
     *
     * <span class="hljs-doctag">@param</span> data {<span class="hljs-doctag">@link</span> Log}
     * <span class="hljs-doctag">@return</span> {<span class="hljs-doctag">@link</span> CompletableFuture&lt;Response&gt;} submit result
     * <span class="hljs-doctag">@throws</span> Exception when submit throw Exception
     */</span>
    <span class="hljs-function">CompletableFuture&lt;Response&gt; <span class="hljs-title">submitAsync</span><span class="hljs-params">(Log data)</span></span>;

    <span class="hljs-comment">/**
     * New member list
     * 新的成员节点列表，一致性协议自行处理相应的成员节点是加入还是离开
     *
     * <span class="hljs-doctag">@param</span> addresses [ip:port, ip:port, ...]
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">memberChange</span><span class="hljs-params">(Set&lt;String&gt; addresses)</span></span>;

    <span class="hljs-comment">/**
     * Consistency agreement service shut down
     * 一致性协议服务关闭
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">shutdown</span><span class="hljs-params">()</span></span>;

}
</code></pre>
<p>For the CP protocol, due to the concept of Leader, it is necessary to provide a method for obtaining who is the current Leader of the CP protocol.</p>
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">CPProtocol</span>&lt;<span class="hljs-title">C</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Config</span>&gt; <span class="hljs-keyword">extends</span> <span class="hljs-title">ConsistencyProtocol</span>&lt;<span class="hljs-title">C</span>&gt; </span>{

	<span class="hljs-comment">/**
	 * Returns whether this node is a leader node
	 *
	 * <span class="hljs-doctag">@param</span> group business module info
	 * <span class="hljs-doctag">@return</span> is leader
	 * <span class="hljs-doctag">@throws</span> Exception
	 */</span>
	<span class="hljs-function"><span class="hljs-keyword">boolean</span> <span class="hljs-title">isLeader</span><span class="hljs-params">(String group)</span> <span class="hljs-keyword">throws</span> Exception</span>;

}
</code></pre>
<p><a name="oJFpB"></a></p>
<h4>Data operation request submission object：Log、GetRequest</h4>
<p>As mentioned above, the consistency protocol is actually for data operations. Data operations are basically divided into two categories: data query and data modification, and at the same time, data isolation between different functional modules must be satisfied. Therefore, the data modification operations and data query operations are explained separately here.</p>
<ol>
<li>Data modification
<ol>
<li>Data modification operation, you must know which functional module this request belongs to</li>
<li>For data modification operations, you must first know what kind of modification operation this data modification operation is for, so that the function module can perform corresponding logical operations for the real data modification operation</li>
<li>For data modification operations, you must know what the modified data is, that is, the request body. In order to make the consistency protocol layer more general, here for the data structure of the request body, the byte[] array is selected</li>
<li>The type of data, because we serialize the real data into a byte[] array, in order to be able to serialize normally, we may also need to record what the type of this data is</li>
<li>The information summary or identification information of this request</li>
<li>The additional information for this request is used to expand the data to be transmitted in the future</li>
</ol>
</li>
</ol>
<p>In summary, it can be concluded that the design of the Log object is as follows</p>
<pre><code class="language-protobuf"><span class="hljs-class"><span class="hljs-keyword">message</span> <span class="hljs-title">Log</span> </span>{
	<span class="hljs-comment">// Function module grouping information</span>
    <span class="hljs-built_in">string</span> <span class="hljs-keyword">group</span> = <span class="hljs-number">1</span>;
    <span class="hljs-comment">// Abstract or logo</span>
    <span class="hljs-built_in">string</span> key = <span class="hljs-number">2</span>;
    <span class="hljs-comment">// Specific request data</span>
    <span class="hljs-built_in">bytes</span> data = <span class="hljs-number">3</span>;
    <span class="hljs-comment">// type of data</span>
    <span class="hljs-built_in">string</span> type = <span class="hljs-number">4</span>;
    <span class="hljs-comment">// More specific data manipulation</span>
    <span class="hljs-built_in">string</span> operation = <span class="hljs-number">5</span>;
    <span class="hljs-comment">// extra information</span>
    map&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>&gt; extendInfo = <span class="hljs-number">6</span>;
}
</code></pre>
<ol start="2">
<li>Data query
<ol>
<li>For data query operations, you must know which function module initiated the request</li>
<li>What are the conditions for data query? In order to be compatible with data query operations of various storage structures, here byte[] is used for storage</li>
<li>The additional information for this request is used to expand the data to be transmitted in the future</li>
</ol>
</li>
</ol>
<p>In summary, the design of the GetRequest object is as follows</p>
<pre><code class="language-protobuf"><span class="hljs-class"><span class="hljs-keyword">message</span> <span class="hljs-title">GetRequest</span> </span>{
	<span class="hljs-comment">// Function module grouping information</span>
    <span class="hljs-built_in">string</span> <span class="hljs-keyword">group</span> = <span class="hljs-number">1</span>;
    <span class="hljs-comment">// Specific request data</span>
    <span class="hljs-built_in">bytes</span> data = <span class="hljs-number">2</span>;
    <span class="hljs-comment">// extra information</span>
    map&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>&gt; extendInfo = <span class="hljs-number">3</span>;
}
</code></pre>
<p><a name="vBig4"></a></p>
<h4>Function modules use consistency protocol：LogProcessor</h4>
<p>After the data operation is submitted through the consistency protocol, each node needs to process the Log or GetRequest object. Therefore, we need to abstract a Log and GetRequest object Processor. Different functional modules implement the processor. ConsistencyProtocol will internally According to the group attributes of Log and GetRequest, the Log and GetRequest objects are routed to a specific Processor. Of course, the Processor also needs to indicate which functional module it belongs to.</p>
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LogProcessor</span> </span>{

    <span class="hljs-comment">/**
     * get data by key
     *
     * <span class="hljs-doctag">@param</span> request request {<span class="hljs-doctag">@link</span> GetRequest}
     * <span class="hljs-doctag">@return</span> target type data
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> Response <span class="hljs-title">onRequest</span><span class="hljs-params">(GetRequest request)</span></span>;

    <span class="hljs-comment">/**
     * Process Submitted Log
     *
     * <span class="hljs-doctag">@param</span> log {<span class="hljs-doctag">@link</span> Log}
     * <span class="hljs-doctag">@return</span> {<span class="hljs-doctag">@link</span> boolean}
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> Response <span class="hljs-title">onApply</span><span class="hljs-params">(Log log)</span></span>;

    <span class="hljs-comment">/**
     * Irremediable errors that need to trigger business price cuts
     *
     * <span class="hljs-doctag">@param</span> error {<span class="hljs-doctag">@link</span> Throwable}
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onError</span><span class="hljs-params">(Throwable error)</span> </span>{
    }

    <span class="hljs-comment">/**
     * In order for the state machine that handles the transaction to be able to route
     * the Log to the correct LogProcessor, the LogProcessor needs to have an identity
     * information
     *
     * <span class="hljs-doctag">@return</span> Business unique identification name
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> String <span class="hljs-title">group</span><span class="hljs-params">()</span></span>;

}
</code></pre>
<p>For the CP protocol, such as the Raft protocol, there is a snapshot design, so we need to separately extend a method for the CP protocol</p>
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LogProcessor4CP</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">LogProcessor</span> </span>{

    <span class="hljs-comment">/**
     * Discovery snapshot handler
     * It is up to LogProcessor to decide which SnapshotOperate should be loaded and saved by itself
     *
     * <span class="hljs-doctag">@return</span> {<span class="hljs-doctag">@link</span> List &lt;SnapshotOperate&gt;}
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;SnapshotOperation&gt; <span class="hljs-title">loadSnapshotOperate</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> Collections.emptyList();
    }

}
</code></pre>
<p><a name="zbsAE"></a></p>
<h4>Summary</h4>
<p>As can be seen from the above points, ConsistencyProtocol is the use interface exposed to the upper layer functional modules. Each ConsistencyProtocol has a backend implemented by a specific consistency protocol. Because Backend cannot be well compatible with nacos existing architecture design, so The additional LogProcessor is designed to solve this problem.<br /><img src="https://cdn.nlark.com/yuque/0/2020/png/333972/1591015048030-8a4bff4a-20ed-46dd-a7f7-98655b22946f.png#align=left&amp;display=inline&amp;height=591&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=591&amp;originWidth=886&amp;size=93327&amp;status=done&amp;style=none&amp;width=886" alt="image.png"><br />同At the time, because the backend inside the consistency protocol layer needs to implement the isolation processing of the data of different business modules, and this piece of logic is implemented by the request object and the group attribute of the LogProcessor<br /><img src="https://cdn.nlark.com/yuque/0/2020/png/333972/1591015155835-a897262e-8e57-409c-bf94-d57bf765c80b.png#align=left&amp;display=inline&amp;height=591&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=591&amp;originWidth=910&amp;size=118083&amp;status=done&amp;style=none&amp;width=910" alt="image.png">
<a name="C1yU6"></a></p>
<h3>Consistent protocol layer workflow</h3>
<p>We can take a look at a sequence diagram, the general workflow of the consistency protocol layer
<img src="https://cdn.nlark.com/yuque/__puml/30b7e270e7aef8bb63136aaffbe5bfbf.svg#lake_card_v2=eyJjb2RlIjoiQHN0YXJ0dW1sXG5cbnBhcnRpY2lwYW50IFwiTWVtYmVyTWFuYWdlclwiIGFzIE5hY29zQ2x1c3RlclxucGFydGljaXBhbnQgXCJCdXNpbmVzc01vZHVsZVwiIGFzIEJpelxucGFydGljaXBhbnQgXCJDb25zaXN0ZW5jeVByb3RvY29sXCIgYXMgUHJvdG9jb2xcbnBhcnRpY2lwYW50IFwiQ0FQQmFja2VuZFwiIGFzIEJhY2tlbmRcbnBhcnRpY2lwYW50IFwiQ29uZmlnXCIgYXMgQ29uZmlnXG5wYXJ0aWNpcGFudCBcIkxvZ1Byb2Nlc3NvclwiIGFzIFByb2Nlc3NvclxucGFydGljaXBhbnQgXCJMb2dcIiBhcyBMb2dcblxuYWN0aXZhdGUgTmFjb3NDbHVzdGVyXG5OYWNvc0NsdXN0ZXIgLT4gTmFjb3NDbHVzdGVyOiBpbml0KCkg5Yid5aeL5YyWTmFjb3Ppm4bnvqRcblxuTmFjb3NDbHVzdGVyIC0-IENvbmZpZzog6I635Y-WQ29uZmln5a-56LGhXG5hY3RpdmF0ZSBDb25maWdcbkNvbmZpZyAtPiBDb25maWc6IOaUtumbhkxvZ1Byb2Nlc3NvcueahOS_oeaBr1xuQ29uZmlnIC0-IE5hY29zQ2x1c3RlclxuZGVhY3RpdmF0ZSBDb25maWdcblxuXG5OYWNvc0NsdXN0ZXIgLT4gUHJvdG9jb2w6IOiOt-WPluaJgOaciUNvbnNpc3RlbmN5UHJvdG9jb2zlrp7njrBcbmFjdGl2YXRlIFByb3RvY29sXG5cbk5hY29zQ2x1c3RlciAtPiBQcm90b2NvbDogaW5pdChDb25maWcpIOaWueazleaJp-ihjFxuXG5kZWFjdGl2YXRlIFByb3RvY29sXG5kZWFjdGl2YXRlIE5hY29zQ2x1c3RlclxuXG5cbkJpeiAtPiBMb2c6IOWIm-W7uuS4gOS4quS6i-WKoeWvueixoVxuYWN0aXZhdGUgQml6XG5hY3RpdmF0ZSBMb2dcblxuXG5Mb2cgLT4gTG9nOiDorr7nva5kYXRhXG5Mb2cgLT4gTG9nOiDorr7nva5rZXlcbkxvZyAtPiBMb2c6IOiuvue9rmNsYXNzTmFtZVxuTG9nIC0-IExvZzog6K6-572uZXh0ZW5kSW5mb1xuTG9nIC0-IEJpelxuZGVhY3RpdmF0ZSBMb2dcblxuQml6IC0-IFByb3RvY29sOiBzdWJtaXQoTG9nKSDosIPnlKjkuIDoh7TmgKfljY_orq7ov5vooYzkuovliqHmj5DkuqRcbmFjdGl2YXRlIFByb3RvY29sXG5cblByb3RvY29sIC0-IEJhY2tlbmQ6IOWGhemDqOS4gOiHtOaAp-WNj-iuruW3peS9nFxuYWN0aXZhdGUgQmFja2VuZFxuXG5CYWNrZW5kIC0-IFByb3RvY29sOiDov5Tlm57lt6XkvZzlpITnkIbnu5PmnpxcbmRlYWN0aXZhdGUgQmFja2VuZFxuXG5Qcm90b2NvbCAtPiBQcm9jZXNzb3I6IOWwhkxvZ-WIhuWPkeWIsOWvueW6lOeahFByb2Nlc3Nvcu-8jOiwg-eUqCBvbkFwcGx5IOaWueazlVxuYWN0aXZhdGUgUHJvdG9jb2xcbmRlYWN0aXZhdGUgUHJvdG9jb2xcblxuUHJvY2Vzc29yIC0-IEJpejog5LqL5Yqh5o-Q5Lqk57uT5p6cXG5cbmRlYWN0aXZhdGUgUHJvY2Vzc29yXG5kZWFjdGl2YXRlIEJpelxuXG5AZW5kdW1sIiwidHlwZSI6InB1bWwiLCJtYXJnaW4iOnRydWUsImlkIjoiNFZpMkwiLCJ1cmwiOiJodHRwczovL2Nkbi5ubGFyay5jb20veXVxdWUvX19wdW1sLzMwYjdlMjcwZTdhZWY4YmI2MzEzNmFhZmZiZTViZmJmLnN2ZyIsImNhcmQiOiJkaWFncmFtIn0=" alt=""><a name="xtBNU"></a></p>
<h3>The implementation option of CP protocol in Nacos consistency protocol layer——JRaft</h3>
<p>After the consistency protocol layer is abstracted, the rest is the choice of concrete consistency protocol implementation. Here we have chosen Ant Financial's open source JRaft, so how can we use JRaf as a backend of the CP protocol? The following simple flow chart describes the initialization process when JRaft is used as a Backend of the CP protocol</p>
<pre><code class="language-java"><span class="hljs-comment">/**
 * A concrete implementation of CP protocol: JRaft
 *
 * &lt;pre&gt;
 *                                           ┌──────────────────────┐               
 *                                           │                      │               
 *            ┌──────────────────────┐       │                      ▼               
 *            │   ProtocolManager    │       │        ┌───────────────────────────┐ 
 *            └──────────────────────┘       │        │for p in [LogProcessor4CP] │ 
 *                        │                  │        └───────────────────────────┘ 
 *                        ▼                  │                      │               
 *      ┌──────────────────────────────────┐ │                      ▼               
 *      │    discovery LogProcessor4CP     │ │             ┌─────────────────┐      
 *      └──────────────────────────────────┘ │             │  get p.group()  │      
 *                        │                  │             └─────────────────┘      
 *                        ▼                  │                      │               
 *                 ┌─────────────┐           │                      │               
 *                 │ RaftConfig  │           │                      ▼               
 *                 └─────────────┘           │      ┌──────────────────────────────┐
 *                        │                  │      │  create raft group service   │
 *                        ▼                  │      └──────────────────────────────┘
 *              ┌──────────────────┐         │                                      
 *              │  JRaftProtocol   │         │                                      
 *              └──────────────────┘         │                                      
 *                        │                  │                                      
 *                     init()                │                                      
 *                        │                  │                                      
 *                        ▼                  │                                      
 *               ┌─────────────────┐         │                                      
 *               │   JRaftServer   │         │                                      
 *               └─────────────────┘         │                                      
 *                        │                  │                                      
 *                        │                  │                                      
 *                        ▼                  │                                      
 *             ┌────────────────────┐        │                                      
 *             │JRaftServer.start() │        │                                      
 *             └────────────────────┘        │                                      
 *                        │                  │                                      
 *                        └──────────────────┘                                      
 * &lt;/pre&gt;
 * 
 * <span class="hljs-doctag">@author</span> &lt;a href="mailto:liaochuntao@live.com"&gt;liaochuntao&lt;/a&gt;
 */</span>
</code></pre>
<p>JRaftProtocol is a concrete implementation of a ConsistencyProtocol when JRaft is used as the backend of the CP protocol. It has a JRaftServer member attribute inside. JRaftServer distributes various API operations of JRaft, such as data operation submission, data query, and member node changes. , Leader node query, etc.</p>
<p><em><strong>Note: The data generated during JRaft operation is in the ${nacos.home}/data/protocol/raft file directory. Different business modules have different file groupings. If the node crashes or shuts down abnormally, clear the files in the directory and restart the node</strong></em></p>
<p>Since JRaft implements the concept of raft group, it is possible to use the design of raft group to create a raft group for each function module. Here is part of the code, which shows how to embed LogProcessor in the state machine and create a Raft Group for each LogPrcessor</p>
<pre><code class="language-java"><span class="hljs-function"><span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">createMultiRaftGroup</span><span class="hljs-params">(Collection&lt;LogProcessor4CP&gt; processors)</span> </span>{
	<span class="hljs-comment">// There is no reason why the LogProcessor cannot be processed because of the synchronization</span>
	<span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.isStarted) {
		<span class="hljs-keyword">this</span>.processors.addAll(processors);
		<span class="hljs-keyword">return</span>;
	}

	<span class="hljs-keyword">final</span> String parentPath = Paths
				.get(ApplicationUtils.getNacosHome(), <span class="hljs-string">"data/protocol/raft"</span>).toString();

	<span class="hljs-keyword">for</span> (LogProcessor4CP processor : processors) {
		<span class="hljs-keyword">final</span> String groupName = processor.group();
		<span class="hljs-keyword">if</span> (multiRaftGroup.containsKey(groupName)) {
			<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> DuplicateRaftGroupException(groupName);
		}

		<span class="hljs-comment">// Ensure that each Raft Group has its own configuration and NodeOptions</span>
		Configuration configuration = conf.copy();
		NodeOptions copy = nodeOptions.copy();
		JRaftUtils.initDirectory(parentPath, groupName, copy);

		<span class="hljs-comment">// Here, the LogProcessor is passed into StateMachine, and when the StateMachine</span>
		<span class="hljs-comment">// triggers onApply, the onApply of the LogProcessor is actually called</span>
		NacosStateMachine machine = <span class="hljs-keyword">new</span> NacosStateMachine(<span class="hljs-keyword">this</span>, processor);

		copy.setFsm(machine);
		copy.setInitialConf(configuration);

		<span class="hljs-comment">// Set snapshot interval, default 1800 seconds</span>
		<span class="hljs-keyword">int</span> doSnapshotInterval = ConvertUtils.toInt(raftConfig
							.getVal(RaftSysConstants.RAFT_SNAPSHOT_INTERVAL_SECS),
					RaftSysConstants.DEFAULT_RAFT_SNAPSHOT_INTERVAL_SECS);

		<span class="hljs-comment">// If the business module does not implement a snapshot processor, cancel the snapshot</span>
		doSnapshotInterval = CollectionUtils
					.isEmpty(processor.loadSnapshotOperate()) ? <span class="hljs-number">0</span> : doSnapshotInterval;

		copy.setSnapshotIntervalSecs(doSnapshotInterval);
		Loggers.RAFT.info(<span class="hljs-string">"create raft group : {}"</span>, groupName);
		RaftGroupService raftGroupService = <span class="hljs-keyword">new</span> RaftGroupService(groupName,
					localPeerId, copy, rpcServer, <span class="hljs-keyword">true</span>);

		<span class="hljs-comment">// Because RpcServer has been started before, it is not allowed to start again here</span>
		Node node = raftGroupService.start(<span class="hljs-keyword">false</span>);
		machine.setNode(node);
		RouteTable.getInstance().updateConfiguration(groupName, configuration);
		RaftExecutor.executeByCommon(() -&gt; registerSelfToCluster(groupName, localPeerId, configuration));

		<span class="hljs-comment">// Turn on the leader auto refresh for this group</span>
		Random random = <span class="hljs-keyword">new</span> Random();
		<span class="hljs-keyword">long</span> period = nodeOptions.getElectionTimeoutMs() + random.nextInt(<span class="hljs-number">5</span> * <span class="hljs-number">1000</span>);
		RaftExecutor.scheduleRaftMemberRefreshJob(() -&gt; refreshRouteTable(groupName),
					nodeOptions.getElectionTimeoutMs(), period, TimeUnit.MILLISECONDS);
		multiRaftGroup.put(groupName,
					<span class="hljs-keyword">new</span> RaftGroupTuple(node, processor, raftGroupService, machine));
	}
}
</code></pre>
<p><a name="4czvB"></a></p>
<h4>Q&amp;A: Why do you want to create multiple raft groups<br /></h4>
<p>Some people may have doubts. Since the LogProcessor has been designed before, you can use a Raft Group. When the state machine is appl, you can route to different LogProcessors according to the Log group attribute. Each function module creates a Raft group, will it consume a lot of resources? <br />As mentioned before, we hope that the modules that work independently do not affect each other. For example, the A module processing Log may cause the application speed to be slow because of the Block operation, or an exception may occur halfway. For the Raft protocol , When the log apply fails, the state machine will not be able to continue to move forward, because if you continue to move forward, due to the previous step of the apply failure, all subsequent applications may fail, which will cause the data of this node and other nodes Data is never consistent. If we put all the modules that work independently in the same raft group, that is, a state machine, for the data processing request processing, the above-mentioned problems will inevitably occur, and a module will be uncontrollable in the apply log. Factors will affect the normal operation of other modules.
<a name="2GyRw"></a></p>
<h3>JRaft operation and maintenance</h3>
<p>In order to allow users to perform simple operation and maintenance of JRaft, such as leader switching, resetting the current Raft cluster members, triggering a node to perform Snapshot operations, etc., a simple HTTP interface is provided for operation, and the interface has certain Limit, that is, only one operation instruction can be executed at a time</p>
<p>1、Switch the leader node of a certain Raft Group</p>
<pre><code class="language-java">POST /nacos/v1/core/ops/raft
{
    <span class="hljs-string">"groupId"</span>: <span class="hljs-string">"xxx"</span>,
    <span class="hljs-string">"command"</span>: <span class="hljs-string">"transferLeader"</span>
    <span class="hljs-string">"value"</span>: <span class="hljs-string">"ip:{raft_port} or ip:{raft_port},ip:{raft_port},ip:{raft_port}"</span>
}
</code></pre>
<p><a name="Fs7VE"></a>
2、Reset a Raft Group cluster member</p>
<pre><code class="language-java">POST /nacos/v1/core/ops/raft
{
    <span class="hljs-string">"groupId"</span>: <span class="hljs-string">"xxx"</span>,
    <span class="hljs-string">"command"</span>: <span class="hljs-string">"resetRaftCluster"</span>,
    <span class="hljs-string">"value"</span>: <span class="hljs-string">"ip:{raft_port},ip:{raft_port},ip:{raft_port},ip:{raft_port}"</span>
}
</code></pre>
<p>Note that this operation is a high-risk operation. This operation and maintenance command can only be used when the n/2 + 1 node of the Raft cluster fails to meet the requirements of more than half of the vote after the crash. It is used to quickly reorganize the remaining nodes to the Raft cluster to provide external Service, but this operation will greatly cause the loss of data<br /></p>
<p><a name="VfG5T"></a>
3、Trigger a Raft Group to perform a snapshot operation</p>
<pre><code class="language-java">POST /nacos/v1/core/ops/raft
{
    <span class="hljs-string">"groupId"</span>: <span class="hljs-string">"xxx"</span>,
    <span class="hljs-string">"command"</span>: <span class="hljs-string">"doSnapshot"</span>,
    <span class="hljs-string">"value"</span>: <span class="hljs-string">"ip:{raft_port}"</span>
}
</code></pre>
<p><a name="m9LfI"></a>
4、Remove a member of a Raft Group</p>
<pre><code class="language-java">POST /nacos/v1/core/ops/raft
{
    <span class="hljs-string">"groupId"</span>: <span class="hljs-string">"xxx"</span>,
    <span class="hljs-string">"command"</span>: <span class="hljs-string">"removePeer"</span>,
    <span class="hljs-string">"value"</span>: <span class="hljs-string">"ip:{raft_port}"</span>
}
</code></pre>
<p><a name="ev3MW"></a>
5、Remove multiple members of a Raft Group in batches</p>
<pre><code class="language-java">POST /nacos/v1/core/ops/raft
{
    <span class="hljs-string">"groupId"</span>: <span class="hljs-string">"xxx"</span>,
    <span class="hljs-string">"command"</span>: <span class="hljs-string">"removePeers"</span>,
    <span class="hljs-string">"value"</span>: <span class="hljs-string">"ip:{raft_port},ip:{raft_port},ip:{raft_port},..."</span>
}
</code></pre>
<p><a name="GzMuP"></a></p>
<h3>JRaft protocol related configuration parameters</h3>
<pre><code class="language-yaml"><span class="hljs-comment">### Sets the Raft cluster election timeout, default value is 5 second</span>
<span class="hljs-string">nacos.core.protocol.raft.data.election_timeout_ms=5000</span>
<span class="hljs-comment">### Sets the amount of time the Raft snapshot will execute periodically, default is 30 minute</span>
<span class="hljs-string">nacos.core.protocol.raft.data.snapshot_interval_secs=30</span>
<span class="hljs-comment">### Requested retries, default value is 1</span>
<span class="hljs-string">nacos.core.protocol.raft.data.request_failoverRetries=1</span>
<span class="hljs-comment">### raft internal worker threads</span>
<span class="hljs-string">nacos.core.protocol.raft.data.core_thread_num=8</span>
<span class="hljs-comment">### Number of threads required for raft business request processing</span>
<span class="hljs-string">nacos.core.protocol.raft.data.cli_service_thread_num=4</span>
<span class="hljs-comment">### raft linear read strategy, defaults to index</span>
<span class="hljs-string">nacos.core.protocol.raft.data.read_index_type=ReadOnlySafe</span>
<span class="hljs-comment">### rpc request timeout, default 5 seconds</span>
<span class="hljs-string">nacos.core.protocol.raft.data.rpc_request_timeout_ms=5000</span>
</code></pre>
<h4>Linear reading parameter analysis</h4>
<ol>
<li><strong>ReadOnlySafe</strong>
<ol>
<li>In this linear read mode, every time a Follower makes a read request, it needs to synchronize with the Leader to submit the site information, and the Leader needs to initiate a lightweight RPC request to prove that it is the Leader to more than half of the Follower, which is equivalent to a Follower read, at least 1 + (n/2) + 1 RPC request is required.</li>
</ol>
</li>
<li><strong>ReadOnlyLeaseBased</strong>
<ol>
<li>In this linear read mode, each time the Follower makes a read request, the Leader only needs to determine whether its Leader lease has expired. If it does not expire, it can directly reply that the Follower is the Leader, but the mechanism has strict requirements on the machine clock. For clock synchronization, consider using this linear read mode.</li>
</ol>
</li>
</ol>
<p><a name="WiLDa"></a></p>
<h2>Nacos embedded distributed ID</h2>
<p>The distributed ID embedded in nacos is Snakeflower, the dataCenterId defaults to 1, and the value of workerId is calculated as follows</p>
<pre><code class="language-yaml"><span class="hljs-string">InetAddress</span> <span class="hljs-string">address;</span>
<span class="hljs-string">try</span> <span class="hljs-string">{</span>
	<span class="hljs-string">address</span> <span class="hljs-string">=</span> <span class="hljs-string">InetAddress.getLocalHost();</span>
<span class="hljs-string">}</span> <span class="hljs-string">catch</span> <span class="hljs-string">(final</span> <span class="hljs-string">UnknownHostException</span> <span class="hljs-string">e)</span> <span class="hljs-string">{</span>
	<span class="hljs-string">throw</span> <span class="hljs-string">new</span> <span class="hljs-string">IllegalStateException(</span>
						<span class="hljs-string">"Cannot get LocalHost InetAddress, please check your network!"</span><span class="hljs-string">);</span>
<span class="hljs-string">}</span>
<span class="hljs-string">byte[]</span> <span class="hljs-string">ipAddressByteArray</span> <span class="hljs-string">=</span> <span class="hljs-string">address.getAddress();</span>
<span class="hljs-string">workerId</span> <span class="hljs-string">=</span> <span class="hljs-string">(((ipAddressByteArray[ipAddressByteArray.length</span> <span class="hljs-bullet">-</span> <span class="hljs-number">2</span><span class="hljs-string">]</span> <span class="hljs-string">&amp;</span> <span class="hljs-number">0</span><span class="hljs-string">B11)</span>
					<span class="hljs-string">&lt;&lt;</span> <span class="hljs-string">Byte.SIZE)</span> <span class="hljs-string">+</span> <span class="hljs-string">(ipAddressByteArray[ipAddressByteArray.length</span> <span class="hljs-bullet">-</span> <span class="hljs-number">1</span><span class="hljs-string">]</span>
					<span class="hljs-string">&amp;</span> <span class="hljs-number">0xFF</span><span class="hljs-string">));</span>
</code></pre>
<p>If you need to manually specify dataCenterId and workerId, add command line parameters in application.properties or startup</p>
<pre><code class="language-yaml"><span class="hljs-comment">### set the dataCenterID manually</span>
<span class="hljs-comment"># nacos.core.snowflake.data-center=</span>
<span class="hljs-comment">### set the WorkerID manually</span>
<span class="hljs-comment"># nacos.core.snowflake.worker-id=</span>
</code></pre>
<p><a name="ZLp5w"></a></p>
<h2>Nacos embedded lightweight Derby-based distributed relational storage</h2>
<p><a name="1B5KV"></a></p>
<h3>Background</h3>
<ol>
<li>If the number of configuration files is small, the cost of supporting a highly available database cluster in the cluster mode is too large, and it is expected to have a lightweight distributed relational storage to solve</li>
<li>Some metadata information storage inside nacos, such as user information, namespace information</li>
<li>Source of ideas:<a href="https://github.com/rqlite/rqlite">https://github.com/rqlite/rqlite</a><br />
<a name="Du2qc"></a></li>
</ol>
<h3>Design ideas</h3>
<p><a name="NzxHa"></a></p>
<h4>aims</h4>
<p>The design goal is to expect nacos to have two data storage modes, one is the current way, the data is stored in an external data source (relational database); the second way is the embedded storage data source (Apache Derby). Users can use the command line parameter configuration to freely use these two data storage modes<br /><img src="https://cdn.nlark.com/yuque/0/2020/png/333972/1591015542106-f14d2579-229f-4bfb-a432-e40854e65d6d.png#align=left&amp;display=inline&amp;height=903&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=903&amp;originWidth=1514&amp;size=237497&amp;status=done&amp;style=none&amp;width=1514" alt="image.png">
<a name="LqUtU"></a></p>
<h4>overall</h4>
<p>Save the SQL context involved in a request operation in order. Then synchronize the SQL context involved in this request through the consensus protocol layer, and then each node parses it and executes it again in a database session in sequence.<br /><img src="https://cdn.nlark.com/yuque/0/2020/png/333972/1587204104465-2270480a-de25-4c84-a11b-6edd2de99e66.png#align=left&amp;display=inline&amp;height=814&amp;margin=%5Bobject%20Object%5D&amp;name=%E6%9C%AA%E5%91%BD%E5%90%8D%E6%96%87%E4%BB%B6%20%281%29.png&amp;originHeight=814&amp;originWidth=1149&amp;size=130886&amp;status=done&amp;style=none&amp;width=1149" alt="未命名文件 (1).png">
<a name="yxFYn"></a></p>
<h4>Related data bearing objects</h4>
<p>The DML statements of the database are select, insert, update, and delete. According to the nature of SQL statements for data operations, they can be divided into two categories: query and update. The select statement corresponds to data query, and the insert, update, and delete statements correspond to Data modification. At the same time, when performing database operations, in order to avoid SQL injection, PreparedStatement is used, so SQL statements + parameters are required, so two Request objects about database operations can be obtained</p>
<ol>
<li>SelectRequest</li>
</ol>
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SelectRequest</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Serializable</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">long</span> serialVersionUID = <span class="hljs-number">2212052574976898602L</span>;
    <span class="hljs-comment">// Query category, because currently using JdbcTemplate, query a single, multiple queries, whether to use RowMapper into an object</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">byte</span> queryType;
    <span class="hljs-comment">// sql语句</span>
    <span class="hljs-comment">// select * from config_info where</span>
    <span class="hljs-keyword">private</span> String sql;
    <span class="hljs-keyword">private</span> Object[] args;
    <span class="hljs-keyword">private</span> String className;
}
</code></pre>
<ol start="2">
<li>ModifyRequest</li>
</ol>
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ModifyRequest</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Serializable</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">long</span> serialVersionUID = <span class="hljs-number">4548851816596520564L</span>;

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> executeNo;
    <span class="hljs-keyword">private</span> String sql;
    <span class="hljs-keyword">private</span> Object[] args;
}
</code></pre>
<p><a name="moKl7"></a></p>
<h4>Configure publishing</h4>
<p>The configuration release operation involves three transactions:</p>
<ol>
<li>config_info saves configuration information</li>
<li>config_tags_relation saves the association relationship between configuration and tags</li>
<li>his_config_info saves a history of configuration operations</li>
</ol>
<p>These three transactions are all configured and released under this big transaction. If we say that we perform a Raft protocol submission for each transaction operation, assume that 1, 2 transactions are successfully applied after being submitted through Raft, and the third transaction is in Raft. Apply fails after submission, then for the big transaction released by this configuration, it needs to be rolled back as a whole, otherwise it will violate the atomicity, then it may be necessary to say that the transaction rollback operation is again Raft submitted, then the overall complexity Rise, and directly introduce the management of distributed transactions, so in order to avoid this problem, we integrate the SQL contexts involved in these three transactions into a large SQL context, and submit the Raft protocol to this large SQL context. It ensures that the three sub-transactions successfully solve the atomicity problem in the same database session. At the same time, because the Raft protocol processes the transaction log serially, it is equivalent to adjusting the transaction isolation level of the database to serialization.</p>
<pre><code class="language-java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addConfigInfo</span><span class="hljs-params">(<span class="hljs-keyword">final</span> String srcIp,
			<span class="hljs-keyword">final</span> String srcUser, <span class="hljs-keyword">final</span> ConfigInfo configInfo, <span class="hljs-keyword">final</span> Timestamp time,
			<span class="hljs-keyword">final</span> Map&lt;String, Object&gt; configAdvanceInfo, <span class="hljs-keyword">final</span> <span class="hljs-keyword">boolean</span> notify)</span> </span>{

	<span class="hljs-keyword">try</span> {
		<span class="hljs-keyword">final</span> String tenantTmp = StringUtils.isBlank(configInfo.getTenant()) ?
					StringUtils.EMPTY :
					configInfo.getTenant();
		configInfo.setTenant(tenantTmp);
        
        <span class="hljs-comment">// Obtain the database primary key through the snowflake ID algorithm</span>
		<span class="hljs-keyword">long</span> configId = idGeneratorManager.nextId(RESOURCE_CONFIG_INFO_ID);
		<span class="hljs-keyword">long</span> hisId = idGeneratorManager.nextId(RESOURCE_CONFIG_HISTORY_ID);

		addConfigInfoAtomic(configId, srcIp, srcUser, configInfo, time,
					configAdvanceInfo);
		String configTags = configAdvanceInfo == <span class="hljs-keyword">null</span> ?
					<span class="hljs-keyword">null</span> :
					(String) configAdvanceInfo.get(<span class="hljs-string">"config_tags"</span>);

		addConfigTagsRelation(configId, configTags, configInfo.getDataId(),
					configInfo.getGroup(), configInfo.getTenant());
		insertConfigHistoryAtomic(hisId, configInfo, srcIp, srcUser, time, <span class="hljs-string">"I"</span>);
		EmbeddedStorageContextUtils.onModifyConfigInfo(configInfo, srcIp, time);
		databaseOperate.blockUpdate();
	}
	<span class="hljs-keyword">finally</span> {
		EmbeddedStorageContextUtils.cleanAllContext();
	}
}

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">long</span> <span class="hljs-title">addConfigInfoAtomic</span><span class="hljs-params">(<span class="hljs-keyword">final</span> <span class="hljs-keyword">long</span> id, <span class="hljs-keyword">final</span> String srcIp,
			<span class="hljs-keyword">final</span> String srcUser, <span class="hljs-keyword">final</span> ConfigInfo configInfo, <span class="hljs-keyword">final</span> Timestamp time,
			Map&lt;String, Object&gt; configAdvanceInfo)</span> </span>{
	...
    <span class="hljs-comment">// 参数处理</span>
    ...
	<span class="hljs-keyword">final</span> String sql =
				<span class="hljs-string">"INSERT INTO config_info(id, data_id, group_id, tenant_id, app_name, content, md5, src_ip, src_user, gmt_create,"</span>
						+ <span class="hljs-string">"gmt_modified, c_desc, c_use, effect, type, c_schema) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"</span>;
	<span class="hljs-keyword">final</span> Object[] args = <span class="hljs-keyword">new</span> Object[] { id, configInfo.getDataId(),
				configInfo.getGroup(), tenantTmp, appNameTmp, configInfo.getContent(),
				md5Tmp, srcIp, srcUser, time, time, desc, use, effect, type, schema, };
	SqlContextUtils.addSqlContext(sql, args);
	<span class="hljs-keyword">return</span> id;
}

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addConfigTagRelationAtomic</span><span class="hljs-params">(<span class="hljs-keyword">long</span> configId, String tagName, String dataId,
			String group, String tenant)</span> </span>{
	<span class="hljs-keyword">final</span> String sql =
				<span class="hljs-string">"INSERT INTO config_tags_relation(id,tag_name,tag_type,data_id,group_id,tenant_id) "</span>
						+ <span class="hljs-string">"VALUES(?,?,?,?,?,?)"</span>;
	<span class="hljs-keyword">final</span> Object[] args = <span class="hljs-keyword">new</span> Object[] { configId, tagName, <span class="hljs-keyword">null</span>, dataId, group,
				tenant };
	SqlContextUtils.addSqlContext(sql, args);
}

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertConfigHistoryAtomic</span><span class="hljs-params">(<span class="hljs-keyword">long</span> configHistoryId, ConfigInfo configInfo,
			String srcIp, String srcUser, <span class="hljs-keyword">final</span> Timestamp time, String ops)</span> </span>{
	...
    <span class="hljs-comment">// 参数处理</span>
    ...
	<span class="hljs-keyword">final</span> String sql =
				<span class="hljs-string">"INSERT INTO his_config_info (id,data_id,group_id,tenant_id,app_name,content,md5,"</span>
						+ <span class="hljs-string">"src_ip,src_user,gmt_modified,op_type) VALUES(?,?,?,?,?,?,?,?,?,?,?)"</span>;
	<span class="hljs-keyword">final</span> Object[] args = <span class="hljs-keyword">new</span> Object[] { configHistoryId, configInfo.getDataId(),
				configInfo.getGroup(), tenantTmp, appNameTmp, configInfo.getContent(),
				md5Tmp, srcIp, srcUser, time, ops };

	SqlContextUtils.addSqlContext(sql, args);
}

<span class="hljs-comment">/**
 * Temporarily saves all insert, update, and delete statements under
 * a transaction in the order in which they occur
 *
 * <span class="hljs-doctag">@author</span> &lt;a href="mailto:liaochuntao@live.com"&gt;liaochuntao&lt;/a&gt;
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SqlContextUtils</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> ThreadLocal&lt;ArrayList&lt;ModifyRequest&gt;&gt; SQL_CONTEXT =
            ThreadLocal.withInitial(ArrayList::<span class="hljs-keyword">new</span>);

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addSqlContext</span><span class="hljs-params">(String sql, Object... args)</span> </span>{
        ArrayList&lt;ModifyRequest&gt; requests = SQL_CONTEXT.get();
        ModifyRequest context = <span class="hljs-keyword">new</span> ModifyRequest();
        context.setExecuteNo(requests.size());
        context.setSql(sql);
        context.setArgs(args);
        requests.add(context);
        SQL_CONTEXT.set(requests);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> List&lt;ModifyRequest&gt; <span class="hljs-title">getCurrentSqlContext</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> SQL_CONTEXT.get();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">cleanCurrentSqlContext</span><span class="hljs-params">()</span> </span>{
        SQL_CONTEXT.remove();
    }

}
</code></pre>
<p>A more intuitive understanding through a timing diagram
<img src="https://cdn.nlark.com/yuque/__puml/618e8997395fbc74433ac4a60f67b6b4.svg#lake_card_v2=eyJjb2RlIjoiQHN0YXJ0dW1sXG5cbmF1dG9udW1iZXJcblxuYWN0b3IgXCJVc2VyXCIgYXMgVXNlclxuXG5wYXJ0aWNpcGFudCBcIkNvbmZpZ1NlcnZpY2VcIiBhcyBTZXJ2aWNlXG5wYXJ0aWNpcGFudCBcIlBlcnNpc3RlbmNlU2VydmljZVwiIGFzIFJlcG9zaXRvcnlcbnBhcnRpY2lwYW50IFwiRGVyYnlcIiBhcyBEQlxucGFydGljaXBhbnQgXCJTUUxDb250ZXh0VXRpbHNcIiBhcyBTUUxDb250ZXh0XG5wYXJ0aWNpcGFudCBcIkxvZ1Byb2Nlc3NvclwiIGFzIFByb2Nlc3NvclxucGFydGljaXBhbnQgXCJDb25zaXN0ZW5jeVByb3RvY29sXCIgYXMgUHJvdG9jb2xcbnBhcnRpY2lwYW50IFwiTG9nXCIgYXMgTG9nXG5cbmFjdGl2YXRlIFVzZXJcblxuVXNlciAtPiBTZXJ2aWNlOiDlj5HotbfphY3nva7lj5HluIPor7fmsYJcbmFjdGl2YXRlIFNlcnZpY2VcblxuU2VydmljZSAtPiBSZXBvc2l0b3J5OiDphY3nva7lj5HluINcbmFjdGl2YXRlIFJlcG9zaXRvcnlcblxuUmVwb3NpdG9yeSAtPiBTUUxDb250ZXh0OiDmi6bmiKrlvZPliY1TUUzkuIrkuIvmlodcbmFjdGl2YXRlIFNRTENvbnRleHRcblxuUmVwb3NpdG9yeSAtPiBSZXBvc2l0b3J5OiBjb21taXQg5pON5L2cXG5cblNRTENvbnRleHQgLT4gUmVwb3NpdG9yeTog5b2T5YmN6K-35rGC5raJ5Y-K55qE5omA5pyJU1FM5LiK5LiL5paHXG5cbmRlYWN0aXZhdGUgU1FMQ29udGV4dFxuXG5SZXBvc2l0b3J5IC0-IExvZzog5p6E5bu66K-35rGC5L2TXG5cbmFjdGl2YXRlIExvZ1xuZGVhY3RpdmF0ZSBMb2dcblxuUmVwb3NpdG9yeSAtPiBQcm90b2NvbDogc3VibWl0KCkg6L-b6KGM6K-35rGC5o-Q5LqkXG5hY3RpdmF0ZSBQcm90b2NvbFxuZGVhY3RpdmF0ZSBSZXBvc2l0b3J5XG5cblByb3RvY29sIC0-IFByb2Nlc3Nvcjogb25BcHBseSgpIOaWueazle-8jOeKtuaAgeacuuWkjeWItkxvZ1xuYWN0aXZhdGUgUHJvY2Vzc29yXG5cblByb2Nlc3NvciAtPiBSZXBvc2l0b3J5OiDmiafooYzmiYDmnInnmoRTUUzkuIrkuIvmlodcbmFjdGl2YXRlIFJlcG9zaXRvcnlcblxuUmVwb3NpdG9yeSAtPiBEQjog5pWw5o2u6JC95bqTXG5hY3RpdmF0ZSBEQlxuXG5EQiAtPiBSZXBvc2l0b3J5OiDnu5PmnZ_lubbov5Tlm57nu5PmnpxcbmRlYWN0aXZhdGUgREJcblxuUmVwb3NpdG9yeSAtPiBQcm9jZXNzb3I6IOi_lOWbnkxvZ0Z1dHVyZeW5tuiuvue9ruacrOasoeaJp-ihjOeahOe7k-aenFxuZGVhY3RpdmF0ZSBSZXBvc2l0b3J5XG5cblByb2Nlc3NvciAtPiBQcm90b2NvbDog6L-U5ZueTG9nRnV0dXJlXG5kZWFjdGl2YXRlIFByb2Nlc3NvclxuXG5Qcm90b2NvbCAtPiBTZXJ2aWNlOiDmnKzmrKHor7fmsYLnmoTnu5PmnpxcbmRlYWN0aXZhdGUgUHJvdG9jb2xcblxuU2VydmljZSAtPiBVc2VyXG5kZWFjdGl2YXRlIFNlcnZpY2VcbmRlYWN0aXZhdGUgVXNlclxuXG5AZW5kdW1sIiwidHlwZSI6InB1bWwiLCJtYXJnaW4iOnRydWUsImlkIjoiVnQxNzciLCJ1cmwiOiJodHRwczovL2Nkbi5ubGFyay5jb20veXVxdWUvX19wdW1sLzYxOGU4OTk3Mzk1ZmJjNzQ0MzNhYzRhNjBmNjdiNmI0LnN2ZyIsImNhcmQiOiJkaWFncmFtIn0=" alt=""><a name="AAJTE"></a></p>
<h3>How to use new features</h3>
<pre><code class="language-bash">./startup.sh -p embedded
</code></pre>
<p>Whether to enable the embedded distributed relational storage activity diagram
<img src="https://cdn.nlark.com/yuque/__puml/1fd656ba3b39fe5de8fea78efdf98dd1.svg#lake_card_v2=eyJjb2RlIjoiQHN0YXJ0dW1sXG5cbigqKSAtLT4gXCJDb25maWcuc3RhcnQoKVwiXG5cbmlmIFwi5Y2V5py65qih5byPXCIgdGhlblxuICAtcmlnaHQtPlt0cnVlXSBcInJldHVybiDpu5jorqTljZXmnLrlrZjlgqjooYzkuLpcIlxuICAtLT4gKCopXG5lbHNlXG4gaWYgXCLlt7LphY3nva7lpJbnva7lrZjlgqhcIiB0aGVuXG4gICAgLS0-W3RydWVdIFwicmV0dXJuIOWklue9ruaVsOaNruWtmOWCqOihjOS4ulwiXG4gICAgLS0-ICgqKVxuIGVsc2VcbiAgICBpZiBcIuW8gOWQr-WGheW1jOWtmOWCqFwiIHRoZW5cbiAgICAgICAgLS0-W3RydWVdIFwicmV0dXJuIOi9u-mHj-WGheW1jOWIhuW4g-W8j-WtmOWCqOihjOS4ulwiXG4gICAgICAgIC0tPiAoKilcbiAgICBlbHNlXG4gICAgICAgIC0-W2ZhbHNlXSBcInJldHVybiDpu5jorqTlpJbnva7mlbDmja7lrZjlgqjooYzkuLpcIlxuICAgICAgICAtLT4gKCopXG5cdFx0ZW5kaWZcbiBlbmRpZlxuZW5kaWZcblxuQGVuZHVtbCIsInR5cGUiOiJwdW1sIiwibWFyZ2luIjp0cnVlLCJpZCI6IkNNN1VDIiwidXJsIjoiaHR0cHM6Ly9jZG4ubmxhcmsuY29tL3l1cXVlL19fcHVtbC8xZmQ2NTZiYTNiMzlmZTVkZThmZWE3OGVmZGY5OGRkMS5zdmciLCJjYXJkIjoiZGlhZ3JhbSJ9" alt=""><a name="9UAXN"></a></p>
<h3>New features related operation and maintenance operations</h3>
<p>Directly query the data stored in each node's derby</p>
<pre><code class="language-java">GET /nacos/v1/cs/ops/derby?sql=select * from config_info

<span class="hljs-keyword">return</span> List&lt;Map&lt;String, Object&gt;&gt;
</code></pre>
<p><a name="YcqO2"></a></p>
<h3>insufficient</h3>
<ol>
<li>Build a distributed data operation synchronization layer on the upper layer of the database, there are restrictions on the operation of the database, such as the first insert operation, then the select operation, and finally the update operation, which is interspersed with query statements in the data modification statement The order of operations is not supported</li>
<li>Limiting the performance of the database, due to the indirect adjustment of the database transaction isolation level to serialization, the concurrency ability is artificially reduced
<a name="7dul8"></a></li>
</ol>
<h3>Future evolution</h3>
<p>Apache Derby official will try to realize the synchronous replication operation of BingLog based on Raft, and realize the database synchronization capability from the bottom</p>
</section><footer class="footer-container" data-reactid="29"><div class="footer-body" data-reactid="30"><img src="/img/nacos_gray.png" data-reactid="31"/><div class="cols-container" data-reactid="32"><div class="col col-12" data-reactid="33"><h3 data-reactid="34">Vision</h3><p data-reactid="35">By providing an easy-to-use service infrastructure such as dynamic service discovery, service configuration, service sharing and management and etc., Nacos help users better construct, deliver and manage their own service platform, reuse and composite business service faster and deliver value of business innovation more quickly so as to win market for users in the era of cloud native and in all cloud environments, such as private, mixed, or public clouds.</p></div><div class="col col-6" data-reactid="36"><dl data-reactid="37"><dt data-reactid="38">Documentation</dt><dd data-reactid="39"><a href="/en-us/docs/what-is-nacos.html" target="_self" data-reactid="40">Overview</a></dd><dd data-reactid="41"><a href="/en-us/docs/quick-start.html" target="_self" data-reactid="42">Quick start</a></dd><dd data-reactid="43"><a href="/en-us/docs/contributing.html" target="_self" data-reactid="44">Developer guide</a></dd></dl></div><div class="col col-6" data-reactid="45"><dl data-reactid="46"><dt data-reactid="47">Resources</dt><dd data-reactid="48"><a href="/en-us/community/index.html" target="_self" data-reactid="49">Community</a></dd><dd data-reactid="50"><a href="https://www.aliyun.com/product/acm?source_type=nacos_pc_20181219" target="_self" data-reactid="51">Cloud Service ACM</a></dd><dd data-reactid="52"><a href="https://www.aliyun.com/product/edas?source_type=nacos_pc_20181219" target="_self" data-reactid="53">Cloud Service EDAS</a></dd><dd data-reactid="54"><a href="https://www.aliyun.com/product/ahas?source_type=nacos_pc_20190225" target="_self" data-reactid="55">Cloud Service AHAS</a></dd></dl></div></div><div class="copyright" data-reactid="56"><span data-reactid="57">@ 2018 The Nacos Authors | An Alibaba Middleware (Aliware) Project</span></div></div></footer></div></div>
	<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
	<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
	<script>
		window.rootPath = '';
  </script>
	<script src="/build/blogDetail.js"></script>
</body>
</html>